package crmdna.mail;

import static crmdna.common.AssertUtils.ensureNotNull;
import static crmdna.common.OfyService.ofy;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class MailStats {
  public static void updateStats(String client, Map<String, MailStatsProp> tagVsMailStatsProp) {
    ensureNotNull(tagVsMailStatsProp, "tagVsMailStatsProp is null");

    List<MailStatsEntity> toSave = new ArrayList<>();
    Map<String, MailStatsEntity> map =
        ofy(client).load().type(MailStatsEntity.class).ids(tagVsMailStatsProp.keySet());

    for (String tag : tagVsMailStatsProp.keySet()) {
      MailStatsProp mailStatsProp = tagVsMailStatsProp.get(tag);

      MailStatsEntity mailStatsEntity;
      if (map.containsKey(tag)) {
        mailStatsEntity = map.get(tag);
      } else {
        mailStatsEntity = new MailStatsEntity();
        mailStatsEntity.tag = tag;
      }

      updateMailStatsEntity(mailStatsEntity, mailStatsProp);
      toSave.add(mailStatsEntity);
    }

    ofy(client).save().entities(toSave);
  }

  public static Map<String, MailStatsEntity> get(String client, Set<String> tags) {
    // TODO: ensure valid client

    return ofy(client).load().type(MailStatsEntity.class).ids(tags);
  }

  public static Map<String, MailStatsProp> getProps(String client, Set<String> tags) {

    Map<String, MailStatsEntity> tagVsEntity = get(client, tags);

    Map<String, MailStatsProp> tagVsProp = new HashMap<>();
    for (String tag : tagVsEntity.keySet()) {
      tagVsProp.put(tag, tagVsEntity.get(tag).toProp());
    }

    return tagVsProp;
  }

  static void updateMailStatsEntity(MailStatsEntity mailStatsEntity, MailStatsProp mailStatsProp) {

    ensureNotNull(mailStatsEntity, "mailStatsEntity is null");
    ensureNotNull(mailStatsProp, "mailStatsProp is null");

    mailStatsEntity.numSendAttempted += mailStatsProp.numSendAttempted;
    mailStatsEntity.numSent += mailStatsProp.numSent;

    mailStatsEntity.numRejects += mailStatsProp.numRejects;
    mailStatsEntity.numHardBounces += mailStatsProp.numHardBounces;
    mailStatsEntity.numSoftBounces += mailStatsProp.numSoftBounces;

    mailStatsEntity.numOpens += mailStatsProp.numOpens;
    mailStatsEntity.numOpensWithin1Hour += mailStatsProp.numOpensWithin1Hour;
    mailStatsEntity.numOpensWithin3Hours += mailStatsProp.numOpensWithin3Hours;
    mailStatsEntity.numOpensWithin24Hours += mailStatsProp.numOpensWithin24Hours;
    mailStatsEntity.numOpensWithin72Hours += mailStatsProp.numOpensWithin72Hours;
    mailStatsEntity.numOpensAfter72Hours += mailStatsProp.numOpensAfter72Hours;
    mailStatsEntity.numMobileOpens += mailStatsProp.numMobileOpens;


    for (String country : mailStatsProp.countryVsNumOpens.keySet()) {
      int value = mailStatsProp.countryVsNumOpens.get(country);

      if (mailStatsEntity.countryVsNumOpens.containsKey(country)) {
        int existing = mailStatsEntity.countryVsNumOpens.get(country);
        mailStatsEntity.countryVsNumOpens.put(country, existing + value);
      } else {
        mailStatsEntity.countryVsNumOpens.put(country, value);
      }
    }

    for (String city : mailStatsProp.cityVsNumOpens.keySet()) {
      int value = mailStatsProp.cityVsNumOpens.get(city);

      if (mailStatsEntity.cityVsNumOpens.containsKey(city)) {
        int existing = mailStatsEntity.cityVsNumOpens.get(city);
        mailStatsEntity.cityVsNumOpens.put(city, existing + value);
      } else {
        mailStatsEntity.cityVsNumOpens.put(city, value);
      }
    }

    mailStatsEntity.numClicks += mailStatsProp.numClicks;

    for (String url : mailStatsProp.urlVsNumClicks.keySet()) {
      int value = mailStatsProp.urlVsNumClicks.get(url);

      if (mailStatsEntity.urlVsNumClicks.containsKey(url)) {
        int existing = mailStatsEntity.urlVsNumClicks.get(url);
        mailStatsEntity.urlVsNumClicks.put(url, existing + value);
      } else {
        mailStatsEntity.urlVsNumClicks.put(url, value);
      }
    }

    mailStatsEntity.numSpams += mailStatsProp.numSpams;
  }
}
